//
// Created by wxd on 2025/9/12.
//
#pragma once

#include <iostream>
#include <vector>
#include <glm/glm.hpp>
#include <glm/trigonometric.hpp>
#include "../wrapper/log/Logger.h"
#include "../wrapper/monitor/GLDebug.hpp"
#include "../global/ChineseOutput.hpp"
#include "../application/app/Application.h"
#include "../glFramework/shader/Shader.h"
#include "../glFramework/texture/Texture.h"
#include "../glFramework/utils/ResourceLoadUtils.h"
#include <memory>

#include "../global/output.hpp"
#include "../application/camera/PerspectiveCamera.h"
#include "../application/camera/control/TrackBallCameraControl.h"
#include "../application/camera/control/GameFPSCameraControl.h"

#include "../glFramework/demo/light/AmbientLight.h"
#include "../glFramework/demo/light/ParallelLight.h"
#include "../glFramework/demo/material/PhongMaterial.h"
#include "../glFramework/geo/Cube.h"
#include "../glFramework/geo/Sphere.h"
#include "../glFramework/demo/mesh/Mesh.h"
#include "../glFramework/demo/renderer/Renderer.h"
#include "../glFramework/constant/engine_uniform.h"


/**
 * 测试引擎的相机系统
 *
 */
struct MvpMatrix {
    glm::mat4 model = glm::mat4(1.0f);
    glm::mat4 view = glm::mat4(1.0f);
    glm::mat4 proj = glm::mat4(1.0f);
};

inline const char* vertexPath = "../assets/shader/phong/specular_mask_phong_vertex.glsl";
inline const char* fragmentPath = "../assets/shader/phong/specular_mask_phong_fragment.glsl";
inline const char* texPath = "../assets/texture/container2.png";
inline const char* texPath2 = "../assets/texture/container2_specular.png";
inline MvpMatrix mvpMatrix;

inline TrackBallCameraControl mController;
inline GameFPSCameraControl mFPSController;
inline PerspectiveCamera mCamera;

inline void onResize(int w, int h) {
    glViewport(0, 0, w, h);
}

inline void onKeyBoard(int key, int action, int mods) {
    if (key == GLFW_KEY_ESCAPE) {
        glfwSetWindowShouldClose(EngineApp.getCurrentWindow(), true);
    }

    mFPSController.onKeyBoard(key, action, mods);
}

inline void onCursor(double xpos, double ypos) {
    mFPSController.onCursor(xpos, ypos);
}

inline void onMouse(int button, int action, int mods) {
    double x, y;
    EngineApp.getCurrentCursorPos(&x, &y);
    mFPSController.onMouse(button, action, x, y);
}

inline void render() {
    ChineseOutput::init();
    EngineApp.initWindowConfig(3, 3, GLFW_OPENGL_CORE_PROFILE,
        2560, 1800,  "FPS Camera Coontrol");
    EngineApp.setResizeCallback(onResize);
    EngineApp.setKeyBoardCallback(onKeyBoard);
    EngineApp.setCursorCallback(onCursor);
    EngineApp.setMouseCallback(onMouse);
    EngineApp.setHideMouseCursor(false);
    EngineApp.init();

    std::unique_ptr<Renderer> renderer = std::make_unique<Renderer>();

    // 初始化相机
    PerspectiveParams param;
    param.fov = 45.f;
    param.aspect = EngineApp.getWindowAspectRatio();
    param.zNear = 0.1f;
    param.zFar = 100.f;
    mCamera.setPerspectiveParams(param);
    mCamera.setCameraParams(glm::vec3(0.f, 0.f, 3.f), glm::vec3(0.f, 1.f, 0.f), glm::vec3(1.f, 0.f, 0.f));
    mFPSController.setMouseCenter(EngineApp.getCurrentWindowWidth(), EngineApp.getCurrentWindowHeight());
    mFPSController.setCamera(&mCamera);
    mFPSController.setSpeed(0.005f);
    mFPSController.setSensitivity(0.03f);
    mFPSController.setPitchRange(89.0f, -89.0f);

    // 初始化光源
    AmbientLight ambient = AmbientLight(
        glm::vec3(0.45f, 0.32f, 0.39f), glm::vec3(0.91f, 0.88f, 0.95f), "AmbientLight"
    );
    ParallelLight parallel = ParallelLight(
        glm::vec3(0.f, 0.f,  -1.f), glm::vec3(0.98f, 0.97f, 0.91f),
        glm::vec3(0.87f, 0.91f, 0.91f), "ParallelLight"
    );

    // 初始化mesh列表（几何数据 + 材质）
    std::vector<std::reference_wrapper<Mesh>> meshQueue;
    meshQueue.reserve(1);
    // 几何对象
    Mesh cubeMesh = Mesh("CubeMesh");
    std::unique_ptr<Cube> cube = std::make_unique<Cube>(1.f, glm::vec3(0.f, 0.f, -3.f));
    // Phong氏材质
    std::unique_ptr<PhongMaterial> material = std::make_unique<PhongMaterial>("PhongMaterial");
    material->loadShader(vertexPath, fragmentPath);
    material->setShininess(256.f);

    std::unique_ptr<Texture> texture = std::make_unique<Texture>(texPath, 0);
    texture->setSamplerName(PhongMaterial::uDiffuseTexture);
    material->setDiffuseTexture(std::move(texture));

    std::unique_ptr<Texture> texture2 = std::make_unique<Texture>(texPath2, 1);
    texture2->setSamplerName(PhongMaterial::uSpecularTexture);
    material->setSpecularTexture(std::move(texture2));
    material->setEnableSpecularMask(true);

    cubeMesh.setMaterial(std::move(material));
    cubeMesh.setGeometry(std::move(cube));
    meshQueue.push_back(cubeMesh);
    meshQueue.shrink_to_fit();

    while (EngineApp.update()) {
        mFPSController.update();
        renderer->render(mCamera, meshQueue, ambient, parallel);
    }
}